package com.evon.yardmanagement.ui.action.transaction;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.apache.struts2.interceptor.ApplicationAware;

import com.evon.yardmanagement.dao.TransporterDAO;
import com.evon.yardmanagement.exception.YardManagementException;
import com.evon.yardmanagement.exception.YardManagementException.ExceptionType;
import com.evon.yardmanagement.model.Car;
import com.evon.yardmanagement.model.Transporter;
import com.evon.yardmanagement.service.CarManagementService;
import com.evon.yardmanagement.service.MemberService;
import com.evon.yardmanagement.transformer.transaction.CarEntryTransformer;
import com.evon.yardmanagement.ui.dto.MemberDTO;
import com.evon.yardmanagement.ui.dto.YardDTO;
import com.evon.yardmanagement.ui.dto.transaction.CarDTO;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;

public class CarExitAction extends ActionSupport implements ModelDriven,
		ApplicationAware {

	private List<MemberDTO> availableMembers = new ArrayList<MemberDTO>();
	private int selectedMemberId;
	
	private List<YardDTO> listYard = new ArrayList<YardDTO>();
	private int selectedYardId;


	private int selectedTransporterId;

	private Map<String, Object> sharedData;
	private List<Transporter> availableTransporter;

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	public CarDTO carDTO;

	public CarExitAction() {
		if (getModel() == null)
			this.carDTO = new CarDTO();
	}

	public String init() {
		//populate the yard list
		listYard = CarManagementService.getAvailableYards();

		sharedData.put("Yards", listYard);

		return SUCCESS;
	}

	public String execute() throws Exception {
		listYard = (List<YardDTO>) sharedData.get("Yards");
		try {
			String enteredChasisNumber = carDTO.getCarChasisNumber();
			if (!isInputValid()) {
				return INPUT;
			}
			Car car = CarManagementService.findCar(enteredChasisNumber, selectedYardId);
			if(car == null){
				addActionMessage("No Car Found with chasis number " + enteredChasisNumber + "in this yard");
				return SUCCESS;
			}
			carDTO = CarEntryTransformer.transform(car);
			// add retrieved object in global data
			sharedData.put("CARDETAILS", carDTO);
			return SUCCESS;
		} catch (YardManagementException yme) {
			if (ExceptionType.RECOVERABLE.equals(yme.getType())) {
				addActionError("Error while retrieving car details, please contact administrator");
				return INPUT;
			} else {
				return ERROR;
			}

		}

	}

	public boolean isInputValid() {
		if (carDTO.getCarChasisNumber() == null
				|| carDTO.getCarChasisNumber().trim().length() == 0) {
			addFieldError("carDTO.carChasisNumber",
					"Please enter Car chasis number");
			return false;
		}
		
		if (selectedYardId <= 0) {
			addFieldError("carDTO.carChasisNumber",
					"Please select Yard.");
			return false;
		}
		return true;
	}

	public boolean isCarParked(Car retrieveingCar) {
		if (retrieveingCar == null) {
			addFieldError("selectedMemberId", "Couldn't find the car");
			return false;
		}
		if ("P".equalsIgnoreCase(retrieveingCar.getParkingStatus()) == false) {
			addFieldError("selectedMemberId", "Car is no longer Parked in Yard");
			return false;
		}
		return true;
	}

	public boolean isCarRetrieved(Car retrieveingCar) {
		if (retrieveingCar == null) {
			addFieldError("selectedMemberId", "Couldn't find the car");
			return false;
		}
		if ("R".equalsIgnoreCase(retrieveingCar.getParkingStatus()) == false) {
			addFieldError("selectedMemberId", "Car is not yet retrieved.");
			return false;
		}
		return true;
	}
	
	public boolean isParkingAlreadyRequested(Car retrieveingCar) {
		if (retrieveingCar == null) {
			addFieldError("selectedMemberId", "Couldn't find the car");
			return false;
		}
		if ('Y' == retrieveingCar.getRetrievalFlag()) {
			addFieldError("selectedMemberId", "Retrieval request is alrady done.");
			return false;
		}
		return true;
	}
	
	public boolean isCarSetForRetrieval(Car retrieveingCar) {
		if ('Y' != retrieveingCar.getRetrievalFlag()) {
			addFieldError("selectedMemberId",
					"Please first request for retrieval.");
			return false;
		}
		return true;
	}

	/**
	 * This method checks if the retrievel request is already present for the given car.
	 * if Yes, show error message else return the list of available drivers for that yard.
	 * 
	 * @return
	 */
	public String retrievalRequest() {
		try {
			if (!isInputValid()) {
				return INPUT;
			}
			listYard = (List<YardDTO>) sharedData.get("Yards");
			
			Car retrieveingCar = CarManagementService.findCar(carDTO.getId());

			if (!isCarParked(retrieveingCar)) {
				return INPUT;
			}
			if (!isParkingAlreadyRequested(retrieveingCar)) {
				return INPUT;
			}

//			if (selectedMemberId == -1) {
//				addFieldError("selectedMemberId",
//						"Please select a retrieveing driver");
//				return INPUT;
//			}
			
			
			// carDTO = CarEntryTransformer.transform(car);
			
			availableMembers = new MemberService()
					.getUnOccupiedMembersOfYard(selectedYardId);
			if(availableMembers != null && !availableMembers.isEmpty()){
				selectedMemberId = availableMembers.get(0).getId();
			}
			carDTO = (CarDTO) sharedData.get("CARDETAILS");
			return SUCCESS;
		} catch (YardManagementException yme) {
			if (ExceptionType.RECOVERABLE.equals(yme.getType())) {
				addActionError("Error while setting car for retrieval, please contact administrator");
				return INPUT;
			} else {
				return ERROR;
			}

		}
	}
	
	/**
	 * 	This method will set the retrieval flag for the given car to true and
	 *  Set the retrieval driver as the selected one and mark the driver occupied.
	 * @return
	 */
	public String retrieveCar(){
		//Set the retrieval request
		if (selectedMemberId == -1) {
		addFieldError("selectedMemberId",
				"Please select a retrieveing driver");
		return INPUT;
	}
		
		carDTO = CarManagementService.setForReteieval(carDTO.getId(),selectedMemberId);
		
		return SUCCESS;
	}
	
	/**
	 * This method checks if the retrievel request is already present for the given car.
	 * if Yes, show error message else return the list of available drivers for that yard.
	 * 
	 * @return
	 */
	public String selectTransporter() {
		try {
			if (!isInputValid()) {
				return INPUT;
			}
			listYard = (List<YardDTO>) sharedData.get("Yards");
			
			Car retrieveingCar = CarManagementService.findCar(carDTO.getId());

			if (!isCarRetrieved(retrieveingCar)) {
				return INPUT;
			}
			
			this.availableTransporter = new TransporterDAO().findAll();
//			
//			if(availableMembers != null || !availableMembers.isEmpty()){
//				selectedMemberId = availableMembers.get(0).getId();
//			}
			carDTO = (CarDTO) sharedData.get("CARDETAILS");
			return SUCCESS;
		} catch (YardManagementException yme) {
			if (ExceptionType.RECOVERABLE.equals(yme.getType())) {
				addActionError("Error while assigning Transporter, please contact administrator");
				return INPUT;
			} else {
				return ERROR;
			}

		}
	}

	public String assignTransporter() {

		carDTO = CarManagementService.findCarDTO(carDTO.getId());
		if (carDTO == null || !"R".equals(carDTO.getParkingStatus())) {
			addActionMessage("Car is not yet retrieved");
			return INPUT;
		}
		listYard = (List<YardDTO>) sharedData.get("Yards");
		// assign the selected transporter
		carDTO = CarManagementService.assignTransporter(carDTO.getId(),
				selectedTransporterId);
		if (carDTO == null) {
			addActionError("Couldn't find the car");
			return INPUT;
		}
		addActionMessage("Transporter assigned successfully");
		return SUCCESS;
	}

	/**
	 * Once the car is confirmed and retrieved , do the following things : 1.
	 * Set the Car retrieval time 2. Set the retrieval driver name 3. Set the
	 * Parking status to R. 4. Set the parking slot to available. 5. Set the key
	 * bin to available. 6. Update the retrieval driver to occupied.
	 * 
	 * @return
	 */
	public String confirmCarRetrieval() {
		if (!isInputValid()) {
			return INPUT;
		}
		listYard = (List<YardDTO>) sharedData.get("Yards");
		Car retrieveingCar = CarManagementService.findCar(carDTO.getId());
		carDTO = CarManagementService.findCarDTO(carDTO.getId());

		if (!isCarParked(retrieveingCar)) {
			return INPUT;
		}

		if (!isCarSetForRetrieval(retrieveingCar)) {
			return INPUT;
		}
		Car retrievedCar = CarManagementService.confirmCarRetrieval(carDTO.getId());

		CarManagementService.setUnOccupied(retrievedCar.getParkingSlot()
				.getId(), retrievedCar.getKeyBox().getId(), retrievedCar.getRetrievalDriver().getId());

		//carDTO = (CarDTO) sharedData.get("CARDETAILS");
		
		addActionMessage("Car Retrieval succesfull for Chasis number - " + carDTO.getCarChasisNumber());
		
		return SUCCESS;
	}

	public Object getModel() {
		return carDTO;
	}

	public List<MemberDTO> getAvailableMembers() {
		return availableMembers;
	}

	public void setAvailableMembers(List<MemberDTO> availableMembers) {
		this.availableMembers = availableMembers;
	}

	public int getSelectedMemberId() {
		return selectedMemberId;
	}

	public void setSelectedMemberId(int selectedMemberId) {
		this.selectedMemberId = selectedMemberId;
	}

	public int getSelectedYardId() {
		return selectedYardId;
	}

	public void setSelectedYardId(int selectedYardId) {
		this.selectedYardId = selectedYardId;
	}

	public CarDTO getCarDTO() {
		return carDTO;
	}

	public void setCarDTO(CarDTO carDTO) {
		this.carDTO = carDTO;
	}

	public int getSelectedTransporterId() {
		return selectedTransporterId;
	}

	public void setSelectedTransporterId(int selectedTransporterId) {
		this.selectedTransporterId = selectedTransporterId;
	}

	public void setApplication(Map<String, Object> application) {
		sharedData = application;

	}

	public List<YardDTO> getListYard() {
		return listYard;
	}

	public void setListYard(List<YardDTO> listYard) {
		this.listYard = listYard;
	}

	public List<Transporter> getAvailableTransporter() {
		return availableTransporter;
	}

	public void setAvailableTransporter(List<Transporter> availableTransporter) {
		this.availableTransporter = availableTransporter;
	}

}
